import json
from datetime import datetime
from decimal import Decimal

from django.db import transaction
from django.http import JsonResponse, HttpResponseBadRequest
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.orders.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.viewmixin import LoginMixin


class OrderSettlementView(LoginMixin, View):
    def get(self, request):
        # 1 获取用户信息user
        user = request.user
        # 2 获取当前用户所有收获地址
        adds = Address.objects.filter(is_deleted=False, user=user)
        # 2.1 转为字典
        addresses = []
        for address in adds:
            addresses.append({
                "id": address.id,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "receiver": address.receiver,
                "mobile": address.mobile
            })
        # 3 获取购物车里的商品数据
        # 3.1 连接redis
        redis_conn = get_redis_connection("carts")
        # 3.2 获取hash
        carts_dict = redis_conn.hgetall("cart_%s" % user.id)
        # 3.3 获取set
        selected_list = redis_conn.smembers("selected_%s" % user.id)
        new_cart_dict = {}
        # 遍历所有选中的id列表
        for sku_id in selected_list:
            count = carts_dict[sku_id]
            new_cart_dict[int(sku_id)] = int(count)

        try:
            skus = SKU.objects.filter(id__in=new_cart_dict.keys())
        except Exception as e:
            print(e)
            return JsonResponse({"code": 400, "errmsg": "数据查询失败"})
        # 3.4 重新组织字典数据
        sku_list = []
        for sku in skus:
            sku_list.append({
                "id": sku.id,
                "name": sku.name,
                "default_image_url": sku.default_image.url,
                "count": new_cart_dict[sku.id],
                "price": sku.price
            })
        freight = Decimal("10.00")
        context = {
            "addresses": addresses,
            "skus": sku_list,
            "freight": freight
        }
        return JsonResponse({"code": 0, "errmsg": "ok", "context": context})


class OrderCommitView(LoginMixin, View):
    """
    提交订单  生成订单和订单里的商品
    路由  post  /orders/commit/

    后端
    接受两个参数  address_id  pay_method
    商品数据可以在redis里自己查 价格自己计算
    """

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 1 获取用户对象user 和 address_id pay_method
        user = request.user
        json_data = json.loads(request.body)
        address_id = json_data.get("address_id")
        pay_method = json_data.get("pay_method")
        # 2 校验数据
        if not all([address_id, pay_method]):
            return HttpResponseBadRequest("缺少参数")
        # 判断address_id是否合法
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            print(e)
            return HttpResponseBadRequest("参数address_id错误")
        # 判断pay_method是否合法
        if pay_method not in {OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']}:
            return HttpResponseBadRequest("参数pay_method错误")
        # 3 把数据保存到数据库
        # 3.1 保存订单数据
        # 生成订单号 年月日时分秒+用户编号 %f微秒 %09d表示显示为9位 左侧不够补0
        # order_id = timezone.localtime().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)
        order_id = datetime.now().strftime('%Y%m%d%H%M%S%f') + ('%09d' % user.id)
        # 总数量计算 临时赋值0
        total_count = 0
        # 总金额计算 临时赋值0
        total_amount = 0
        freight = Decimal("10.00")
        # 根据pay_method来选择一个订单状态status
        # 如果是支付宝 那么状态就是待付款 否则就是待发货
        status = OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else \
            OrderInfo.ORDER_STATUS_ENUM['UNSEND']
        with transaction.atomic():
            # 创建保存点
            save_id = transaction.savepoint()
            try:
                order = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    total_count=total_count,
                    total_amount=total_amount,
                    freight=freight,
                    pay_method=pay_method,
                    status=status
                )
                print(order)
            except Exception as e:
                print(e)
                return HttpResponseBadRequest('订单保存失败')
            # 3.2 保存订单的商品数据
            # 连接redis
            redis_conn = get_redis_connection("carts")
            # 获取hash
            carts_dict = redis_conn.hgetall("cart_%s" % user.id)
            # 获取set
            selected_list = redis_conn.smembers("selected_%s" % user.id)
            new_cart_dict = {}
            # 遍历所有选中的id列表
            for sku_id in selected_list:
                # 把数据存到新的字典new_cart_dict 并且转为int
                count = carts_dict[sku_id]
                new_cart_dict[int(sku_id)] = int(count)
            try:
                # new_cart_dict 是所有选中的商品的id和数量
                skus = SKU.objects.filter(id__in=new_cart_dict.keys())
            except Exception as e:
                print(e)
                # 回滚到保存点
                transaction.savepoint_rollback(save_id)
                return JsonResponse({"code": 400, "errmsg": "数据查询失败"})
            try:
                # 遍历skus 生成每个sku的订单商品数据 order_goods对象
                for sku in skus:
                    while True:
                        # 读取原始库存
                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        # 判断库存是否够 count<=stock
                        count = new_cart_dict[sku.id]
                        if count > sku.stock:
                            # 回滚到保存点
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({"code": 400, "errmsg": "库存不足"})
                        # 如果库存够 stock-=count sales+=count
                        # sku.stock -= count
                        # sku.sales += count
                        # sku.save()
                        new_stock = origin_stock - count
                        new_sales = origin_sales + count
                        # result 是更新的数据条数
                        result = SKU.objects.filter(id=sku.id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        if result == 0:
                            continue
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=count,
                            price=sku.price
                        )
                        # 计算订单 总数量计算和金额计算
                        order.total_count += count
                        order.total_amount += count * sku.price
                        break
                # 总价 加上运费
                order.total_amount += order.freight
                # 保存对象
                order.save()
            except Exception as e:
                print(e)
                # 回滚到保存点
                transaction.savepoint_rollback(save_id)
                return HttpResponseBadRequest('订单保存失败')
        # 把redis里购物车中商品信息移除
        redis_conn.hdel("cart_%s" % user.id, *selected_list)
        redis_conn.srem("selected_%s" % user.id, *selected_list)
        # 4 返回响应
        return JsonResponse({"code": 0, "errmsg": "ok", "order_id": order_id})
